<?php

// 获取章节信息
// https://www.ximalaya.com/revision/album/v1/getTracksList?albumId=72465969&pageNum=1&pageSize=30

/*
return Dt.AES.decrypt({
                    ciphertext: Rt.enc.Base64url.parse(t)
                }, Dt.enc.Hex.parse("aaad3e4fd540b0f79dca95606e72bf93"), {
                    mode: Dt.mode.ECB,
                    padding: Dt.pad.Pkcs7
                }).toString(Dt.enc.Utf8)
*/
class Xmly
{
	private $chapter_url = 'https://www.ximalaya.com/revision/album/v1/getTracksList';
	
	private $book_id = ''; // 采集书 ID
	private $chapter_page_num =1; // 采集章节第几页
	private $chapter_page_size =30; // 一页章节显示多少条
	private $chapter_page_total = 1; // 总共分多少页面
  private $header = []; // cookie
	
	private $aes_key = 'aaad3e4fd540b0f79dca95606e72bf93';
	
	public function __construct($book_id, $page_num, $page_size, $header)
	{
    // 检查章节信息是否存在
    if (is_file(__DIR__ . '/chapter')) {
      unlink(__DIR__ . '/chapter');
    }
    // 检查目录是否存在
    if (!is_dir(__DIR__ . '/content')) {
      mkdir(__DIR__ . '/content', 0777, true);
    }
		$this->book_id = $book_id;
		$this->chapter_page_num = $page_num;
		$this->chapter_page_size = $page_size;
    $this->header = $header;
	}
	
	/**
	 * 获取章节目录
	 */
	public function getChapter()
	{
		if ($this->chapter_page_num > $this->chapter_page_total) {
			echo "章节获取完成\n";
			return;
		}
		echo "第" . $this->chapter_page_num . "页采集开始\n";
		// 获取 第一页 的章节信息
		$url = $this->chapter_url . '?albumId=' . $this->book_id . '&pageNum=' . $this->chapter_page_num . '&pageSize=' . $this->chapter_page_size;

		$res = $this->cur_get($url);
		
		$arr = json_decode($res, true);
		if ($arr['ret'] === 200) {
			$data = $arr['data'];
			$total = $data['trackTotalCount'];
			$this->chapter_page_total = ceil($total/$this->chapter_page_size);
			$this->chapter_page_num += 1;
			
			if (is_file(__DIR__ . '/chapter')) {
				$tmp_arr = require(__DIR__ . '/chapter');
			} else {
				$tmp_arr = [];
			}
			
			$tmp_arr = array_merge($tmp_arr, $data['tracks']);
			file_put_contents(__DIR__ . '/chapter', "<?php\nreturn " . var_export($tmp_arr, true) . ';');

			$this->getChapter();
		}
	}

  public function getSourceDowinload()
  {
    $tmp_arr = require(__DIR__ . '/chapter');
    foreach($tmp_arr as $k => $item) {
      $url = 'https://www.ximalaya.com/mobile-playpage/track/v3/baseInfo/' . $this->getMillisecond()  . '?device=web&trackId=' . basename($item['url']) . '&trackQualityLevel=1';
	 
      $res = $this->cur_get($url, $this->header);
      $arr = json_decode($res, true);
      $en_url = $arr['trackInfo']['playUrlList'][0]['url'];
      $de_url = $this->decryptAes($en_url, $this->aes_key);
      list($file_name) = explode('?', $de_url);
      $file_info = pathinfo($file_name);
      $extension = $file_info['extension'];
      list($name) = explode('【', $item['title']);
      $name = trim($name);
      $nameArr = explode(' ', $name);
      $name = array_pop($nameArr);
      $file_name = $k . '_' . $name . '.' . $extension;
	  $file_path = __DIR__ . '/content/' . $file_name;

	  if (is_file($file_path)) {
		  if (0 < filesize($file_path)) {
			  continue;
		  }
	  }
	  
      
      $this->file_download($de_url, __DIR__ . '/content/' . $file_name, $head);
      echo $file_name, "\n";//exit;
	    usleep(50);
      // print_r($de_url);exit;
    }
  }

  private function getMillisecond()
  {
    list($msec, $sec) = explode(' ', microtime());
    $msectime = (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);

    return substr($msectime, 0, 13);
  }
	
	public function decryptAes($str, $key)
	{
		$str = strtr($str, '-_', '+/');
		$ciphertext = base64_decode($str); 
		$key = hex2bin($key);
		$decrypted = openssl_decrypt($ciphertext, 'AES-128-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING); 
		$decrypted = rtrim($decrypted, "\0");
		// $decrypted = rtrim($decrypted, chr(2));
		preg_match('/([a-z:.\/\d\-A-Z?\=&_]+)/', $decrypted, $arr);
		// print_r($arr);exit;
		return $arr[0];
	}
	
  private function file_download($url, $file_name, $head = [])
  {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL,$url);
    file_put_contents(__DIR__ . '/url', $url);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    // 设置请求头
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    $fp =  fopen($file_name, 'w+');
    curl_setopt($ch, CURLOPT_FILE, $fp);
    curl_exec ($ch);
    curl_close ($ch);
    fclose($fp);
  }

	/**
	 * curl get请求
	 *
	 *
	 */
	private function cur_get($url, $header = [])
	{
		$ch = curl_init();
		
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_HEADER, 0);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
		// 设置请求头
		curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
	
		$output = curl_exec($ch);
		
		curl_close($ch);
		
		return $output;
	}
	
}

$header = [
  // cookie信息
];
$book_id = ''; // 书籍ID
$obj = new Xmly($book_id, 1, 30, $header);
$obj->getChapter();
$obj->getSourceDowinload();
